package ctr_layer;

import java.util.Date;
import java.util.List;

import model_layer.Customer;
import model_layer.Product;
import model_layer.Sale;
import model_layer.SaleLineItem;
import model_layer.StaffMember;
import db_layer.CustomerDB;
import db_layer.ProductDB;
import db_layer.SaleDB;

/**
 * This class holds control over creating new and finding and deleting existing sales.
 * IMPORTANT!
 * For proper operations on the sales, each window should use it's own object of SaleCtr.
 * @author Rafal Markiewicz
 *
 */
public class SaleCtr
{
	private Sale sale;
	private SaleLineItem current_item;
	private CustomerDB cust_db;
	private ProductDB prod_db;
	private SaleDB sale_db;

	public SaleCtr()
	{
		sale = null;
		cust_db = new CustomerDB();
		prod_db = new ProductDB();
		sale_db = new SaleDB();
	}
	
	public Sale find_sale(int id)
	{
		return sale_db.find_sale("id", id, true);
	}
	
	public List<Sale> find_all_sales()
	{
		return sale_db.find_all_sales(false);
	}
	
	public boolean delete_sale(int id)
	{
		return sale_db.delete_sale(id);
	}
	
	/**
	 * Creates a new sale to work on, if none exists.
	 * If a sale is already worked on this function does nothing (except for printing an error message)
	 * @return created sale if there was none, or null if there was an existing sale that was currently worked on
	 */
	public Sale make_new_sale()
	{
		if(sale == null)
		{
			sale = new Sale();
			return sale;
		}
		System.err.println("Previous sale has not been saved or discarded, cannot begin working on new sale.");
		return null;
	}
	
	/**
	 * This method selects a desired customer for the sale that is currently worked on. 
	 * Prior to calling this function, a make_new_sale function must have been called (not necessarily directly before it).
	 * Otherwise this function will produce a null pointer exception.
	 * @param cust_id -> the id of the customer to be set
	 * @return customer that was found or null if no customer with this id was found
	 */
	public Sale set_customer_with_id(String cust_id)
	{
		if (sale.getCustomer() == null || !sale.getCustomer().getId().equals(cust_id))
		{
			Customer cust = cust_db.find_customer("id", Integer.parseInt(cust_id));
			if(cust != null && cust.isDeleted())
			{
				cust = null;
			}
			sale.setCustomer(cust);
			sale.calculate_price();
		}

		return sale;
	}
	
	/**
	 * This method selects a desired customer for the sale that is currently worked on. 
	 * Prior to calling this function, a make_new_sale function must have been called (not necessarily directly before it).
	 * Otherwise this function will produce a null pointer exception.
	 * @param cust_name -> the name of the customer to be set
	 * @return customer that was found or null if no customer with this name was found
	 */
	public Sale set_customer_with_name(String cust_name)
	{	
		if (sale.getCustomer() == null || !sale.getCustomer().getName().equals(cust_name))
		{
			Customer cust;
			if (cust_name == null || cust_name.equals(""))
			{
				cust = null;
			}
			else
			{
				cust = cust_db.find_customer("name", cust_name);
			}
			if(cust != null && cust.isDeleted())
			{
				cust = null;
			}
			sale.setCustomer(cust);
			sale.calculate_price();
		}
		return sale;
	}

	
	public SaleLineItem set_product_by_id(String id)
	{
		if(current_item == null)
		{
			current_item = new SaleLineItem();
		}
		if(sale.get_item_by_id(id) != null)
		{
			return null;
		}
		if(!(current_item.getProduct() != null && current_item.getProduct().getId().equals(id)))
		{
			Product prod = prod_db.find_product("id", Integer.parseInt(id));
			if(prod != null && !prod.isDeleted())
			{
				current_item.setProduct(prod);
				return current_item;
			}
			return null;
		}
		return current_item;
	}
	
	public SaleLineItem set_product_by_name(String name)
	{
		if(current_item == null)
		{
			current_item = new SaleLineItem();
		}
		if(sale.get_item_by_name(name) != null)
		{
			return null;
		}
		else if(name != null && name.length() > 0)
		{
			Product prod = prod_db.find_product("name", name);
			if(prod != null && !prod.isDeleted())
			{
				current_item.setProduct(prod);
				return current_item;
			}
		}
		return null;
	}
	
	public void set_amount(int amount)
	{
		if(current_item == null)
		{
			current_item = new SaleLineItem();
		}
		current_item.setAmount(amount);
	}
	
	public SaleLineItem add_current_item()
	{
		current_item.calculate_price();
		sale.add_item(current_item);
		SaleLineItem temp = current_item;
		current_item = null;
		return temp;
	}
	
	
	/**
	 * 
	 * @param old_id -> id of the previous product that occupied this row
	 * @param name -> name of the new "to be updated" product
	 * @return product if the product already exists on that position if the sale, product if the product doesn't exist in the sale,
	 *  null if the product doesn't exist in db or if the update would lead to existence of two same products in sale
	 */
	public SaleLineItem update_product_by_name(String old_id, String name)
	{
		if(name != null && name.length() > 0)
		{
			SaleLineItem item = sale.check_for_repeated_insert(old_id, name);
			if(item == null)
			{
					Product prod = prod_db.find_product("name", name);
		
					if(prod!= null && !prod.isDeleted())
					{
						return sale.update_product(old_id, prod);
					}
			}
			return item;
		}
		return null;
	}
	
	public SaleLineItem update_product_by_id(String old_id, String id)
	{
		Product prod;
		if(old_id.equals(id))
		{
			return sale.get_item_by_id(id);
		}
		else
		{
			prod = prod_db.find_product("id", Integer.parseInt(id));
			if(prod != null && !prod.isDeleted())
			{
				return sale.update_product(old_id, prod);
			}
			return null;
		}
	}
	
	public SaleLineItem update_amount(String id, int amount)
	{
		return sale.update_amount(id, amount);
	}
	
	
	/**
	 * This method removes a product from the sale that is currently being worked on.
	 * @param prod_id -> the id of the product to be removed
	 */
	public void remove_product(String prod_id)
	{
		sale.remove_item(prod_id);
	}
	
	/**
	 * This method sets a special discount for the sale. The discount amount must be in bounds <0:100> or else the discount won't be set.
	 * @param special_discount -> the amount of the special discount set for the sale
	 * @return sale if the discount is within bounds <0:100), null otherwise
	 */
	public Sale make_special_discount(String discount)
	{
		try
		{
			float special_discount = Float.parseFloat(discount);
			if(special_discount >= 100 || special_discount < 0)
			{
				return null;
			}
			sale.setSpecial_discount(special_discount);
			sale.calculate_price();
			return sale;
		}
		catch(NumberFormatException e)
		{
			return null;
		}
		
		
	}
	
	/**
	 * Gets the current sale with all new changes applied and recalculated price.
	 * @return current sale
	 */
	public Sale get_current_sale()
	{
		sale.calculate_price();
		return sale;
	}
	
	/**
	 * Sets a current date as a date of the sale and saves the sale in the database.
	 * It also allows creation of another sale through currently used window.
	 * @param current_account -> the account (StaffMember) that made this sale
	 * @return true if the sale was successfully saved, false otherwise
	 */
	public int save_sale(StaffMember current_account)
	{
		Date current_date = new Date();
		sale.setSale_date(current_date);
		sale.setStaff_member(current_account);
		int return_code = sale_db.insert_sale(sale);
		if(return_code == 1)
		{
			sale = null;
		}
		return return_code;
	}
	
	/**
	 * Discard all changes and allow for creation of another sale through currently used window.
	 */
	public void discard_sale()
	{
		sale = null;
	}

}
